﻿using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.DirectoryServices.AccountManagement;
using JQuery.WebKit.Common.Caching;

namespace JQuery.WebKit.Common.ActiveDirectory
{
    [Serializable]
    public class GroupInfo : ADObject
    {
        private string _emailAddress;
        #region public string EmailAddress
        /// <summary>
        /// Get/Sets the EmailAddress of the GroupInfo
        /// </summary>
        /// <value></value>
        public string EmailAddress
        {
            get { return _emailAddress; }
            set { _emailAddress = value; }
        }
        #endregion

        #region public override ADObjectType ObjectType
        /// <summary>
        /// Gets the ObjectType of the GroupInfo
        /// </summary>
        /// <value></value>
        public override ADObjectType ObjectType
        {
            get { return ADObjectType.Group; }
        }
        #endregion

        #region public GroupInfo()
        /// <summary>
        /// Initializes a new instance of the <b>GroupInfo</b> class.
        /// </summary>
        public GroupInfo()
            : this(string.Empty, ADContextType.Unknown, null)
        {

        }
        #endregion

        #region public GroupInfo(string groupName, ADContextType contextType, GroupPrincipal groupPrincipal)
        /// <summary>
        /// Initializes a new instance of the <b>GroupInfo</b> class.
        /// </summary>
        /// <param name="groupName"></param>
        /// <param name="contextType"></param>
        /// <param name="groupPrincipal"></param>
        public GroupInfo(string groupName, ADContextType contextType, string distinguishedName)
            : base(groupName, contextType, distinguishedName)
        {
        }
        #endregion

        //#region public static GroupInfo GetGroupInfo(GroupPrincipal groupPrincipal, ADContextType groupContextType)
        ///// <summary>
        ///// 
        ///// </summary>
        ///// <param name="groupPrincipal"></param>
        ///// <param name="groupContextType"></param>
        ///// <returns></returns>
        //public static GroupInfo GetGroupInfo(GroupPrincipal groupPrincipal, ADContextType groupContextType)
        //{
        //    if (groupPrincipal == null)
        //    {
        //        return null;
        //    }
        //    GroupInfo gInfo = new GroupInfo(groupPrincipal.Name, groupContextType, groupPrincipal);
        //    gInfo.DisplayName = string.IsNullOrEmpty(groupPrincipal.DisplayName) ? groupPrincipal.Name : groupPrincipal.DisplayName;

        //    return gInfo;
        //}
        //#endregion

        public static GroupInfo GetGroupInfo(DirectoryEntry groupEntry, ADContextType groupContextType)
        {
            if (groupEntry == null)
            {
                return null;
            }

            PropertyValueCollection accountName = groupEntry.Properties["samaccountname"];
            PropertyValueCollection dn = groupEntry.Properties["distinguishedName"];

            if (accountName == null || dn == null ||
                accountName.Value == null || dn.Value == null)
            {
                return null;
            }

            //GroupInfo gInfo = new GroupInfo(groupEntry.Name, groupContextType, groupEntry.Path);
            //gInfo.DisplayName = groupEntry.Name;
            GroupInfo gInfo = new GroupInfo(accountName.Value.ToString(), groupContextType, dn.Value.ToString());
            foreach (PropertyValueCollection prop in groupEntry.Properties)
            {
                if (prop.Value == null)
                {
                    continue;
                }
                Console.WriteLine(string.Format("{0} - {1}", prop.PropertyName, prop.Value.ToString()));
                switch (prop.PropertyName.ToLower())
                {
                    case "cn":
                    case "displayname":
                        gInfo.DisplayName = prop.Value.ToString();
                        break;
                    case "distinguishedname":
                        break;
                    case "mail":
                        gInfo.EmailAddress = prop.Value.ToString();
                        break;
                    default:
                        break;
                }
            }
            return gInfo;
        }

        public IList<ADObject> GetMembers(bool refreshCache)
        {
            return GetMembers(ContextType, refreshCache);
        }

        //public IList<ADObject> GetMembers(ADContextType contextType)
        //{
        //    List<ADObject> info = new List<ADObject>();
        //    if (_objectPrincipal == null)
        //    {
        //        return info;
        //    }

        //    ContextType groupType = (ContextType)Enum.Parse(typeof(ContextType), contextType.ToString(), true);
        //    PrincipalContext groupContext = new PrincipalContext(groupType);

        //    PrincipalSearchResult<Principal> sr = (_objectPrincipal as GroupPrincipal).GetMembers(true);
        //    foreach (Principal princ in sr)
        //    {
        //        if (princ is GroupPrincipal)
        //        {
        //            info.Add(GroupInfo.GetGroupInfo(princ as GroupPrincipal, ContextType));
        //        }
        //        if (princ is UserPrincipal)
        //        {
        //            info.Add(UserInfo.GetUserInfo(princ as UserPrincipal, ContextType));
        //        }
        //    }

        //    return info;
        //}

        public IList<ADObject> GetMembers(ADContextType contextType, bool refreshCache)
        {
            IList<ADObject> info = (List<ADObject>)Cache.Current.GetItem(string.Format("ADObject_{0}_{1}_members", DistinguishedName, contextType));
            if (info != null && !refreshCache)
            {
                return info;
            }
            info = new List<ADObject>();
            ContextType groupType = (ContextType)Enum.Parse(typeof(ContextType), contextType.ToString(), true);
            PrincipalContext groupContext = new PrincipalContext(groupType);

            //using (DirectoryEntry entry = new DirectoryEntry(this.DistinguishedName))
            {
                DirectorySearcher src = new DirectorySearcher(string.Format("(CN={0})", this.Name));
                foreach (SearchResult res in src.FindAll())
                {
                    ResultPropertyValueCollection member = (ResultPropertyValueCollection)res.Properties["member"];
                    if (member == null)
                    {
                        continue;
                    }
                    foreach (string dn in member)
                    {
                        using (DirectoryEntry memberEntry = new DirectoryEntry(string.Format("LDAP://{0}", dn)))
                        {
                            if (dn.ToLower().Contains("group"))
                            {
                                info.Add(GroupInfo.GetGroupInfo(memberEntry, ContextType));
                            }
                            if (dn.ToLower().Contains("user"))
                            {
                                info.Add(UserInfo.GetUserInfo(memberEntry, ContextType));
                            }
                        }
                    }
                }
            }

            Cache.Current.RemoveItem(string.Format("ADObject_{0}_{1}_members", DistinguishedName, contextType));
            Cache.Current.AddItem(string.Format("ADObject_{0}_{1}_members", DistinguishedName, contextType), info);

            return info;
        }
    }
}
